﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MadProps;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;

namespace MadPropsDemo.RecipeEditor
{
    [Meta.Tracking(Tracking.Ignored)]
    public class ViewModel : BaseModel
    {
        public static readonly ViewModel Schema = BuildSchema<ViewModel>();
        internal readonly MadProps.ChangeTracking.ChangeTracker changeTracker;

        public Commands Commands { get; internal set; }

        public readonly IProp<Recipe> Recipe;

        [Meta.Tracking(Tracking.Tagalong)]
        public readonly IProp<Ingredient> SelectedIngredient;

        // These should be made "real" attributes (as opposed to
        // arbitrarily-keyed), but I'm feeling lazy right now.
        [Meta.ArbitraryDecimal("Minimum", "0.1")]
        [Meta.ArbitraryDecimal("Maximum", "10")]
        [Meta.ArbitraryDecimal("Increment", "0.1")]
        [Meta.DisplayName("Scale Factor")]
        public IProp<decimal> CustomScaleFactor { get; protected set; }

        [ReadOnly(true)]
        public IProp<string> IngredientSummary { get; protected set; }

        public readonly IProp<string> UnsavedChangesText;

        internal ViewModel()
        {
            changeTracker = new MadProps.ChangeTracking.ChangeTracker();

            TheRecipe = new Recipe();

            var ing = new Ingredient();
            ing.Name.Value = "Beef";
            ing.Quantity.Value = 2;
            ing.UnitOfMeasure.Value = "lbs";
            TheRecipe.Ingredients.Add(ing);

            ing = new Ingredient();
            ing.Name.Value = "Potatoes";
            ing.Quantity.Value = 4;
            TheRecipe.Ingredients.Add(ing);

            TheSelectedIngredient = TheRecipe.Ingredients.First();

            CustomScaleFactor.Value = 1;

            UpdateIngredientSummary();

            changeTracker.Subscribe(this);
        }

        protected override void OnPropChanged(PropChangedEventArgs args)
        {
            base.OnPropChanged(args);

            var changes = changeTracker.SummarizeChanges();
            if (string.IsNullOrEmpty(changes))
            {
                UnsavedChangesText.Value = "";
            }
            else
            {
                UnsavedChangesText.Value = "Unsaved Changes";
            }

            if (args.Prop.IsAny(
                this.Recipe, this.CustomScaleFactor, Ingredient.Schema.Name,
                Ingredient.Schema.Quantity, Ingredient.Schema.UnitOfMeasure))
            {
                UpdateIngredientSummary();
            }
        }

        void UpdateIngredientSummary()
        {
            StringBuilder summary = new StringBuilder();
            foreach (var ingredient in TheRecipe.Ingredients)
            {
                decimal quantity = ingredient.Quantity.Value * this.CustomScaleFactor.Value;
                string unitOfMeasure = ingredient.UnitOfMeasure.Value;
                string name = ingredient.Name.Value;

                summary.AppendFormat("{0} {1} of {2}",
                    quantity, unitOfMeasure, name).AppendLine();
            }

            IngredientSummary.Value = summary.ToString();
        }

        internal Recipe TheRecipe
        {
            get { return Recipe.Value; }
            set { Recipe.Value = value; }
        }

        internal Ingredient TheSelectedIngredient
        {
            get { return SelectedIngredient.Value; }
            set { SelectedIngredient.Value = value; }
        }

        internal System.Collections.ObjectModel.ObservableCollection<Ingredient> Ingredients
        {
            get { return TheRecipe.Ingredients; }
        }

        int GetSelectedIndex()
        {
            return Ingredients.IndexOf(TheSelectedIngredient);
        }

        internal void MoveDown()
        {
            int index = GetSelectedIndex();
            if (index < Ingredients.Count - 1)
            {
                Ingredients.Move(index, index + 1);
                UpdateIngredientSummary();
            }
        }

        internal void MoveUp()
        {
            int index = GetSelectedIndex();
            if (index > 0)
            {
                Ingredients.Move(index, index - 1);
                UpdateIngredientSummary();
            }
        }

        internal void AddIngredient()
        {
            var ingredient = new Ingredient();
            Ingredients.Add(ingredient);
            TheSelectedIngredient = ingredient;
            UpdateIngredientSummary();
        }

        internal void RemoveIngredient()
        {
            if (TheSelectedIngredient != null)
            {
                int index = GetSelectedIndex();
                Ingredients.Remove(TheSelectedIngredient);

                if (index < Ingredients.Count)
                {
                    TheSelectedIngredient = Ingredients[index];
                }
                else
                {
                    TheSelectedIngredient = Ingredients.LastOrDefault();
                }

                UpdateIngredientSummary();
            }
        }
    }
}
